#include "server.h"
#include <QVector>

const int constSec = 1000;
Server::Server()
{
    if (this->listen(QHostAddress::Any,2323))
    {
        qDebug() << tr("Сервер запущен");

    }
    else
    {
        qDebug() << tr("Ошибка при запуске сервера! Возможно сервер уже запущен.");
    }
    d_nextBlockSize = 0;
    d_numClients = 0;
}

void Server::incomingConnection(qintptr socketDescriptor)       // обработка подключения нового клиента
{
    if(socketDescriptor == -1)
    {
        qFatal("ERROR! socketDescription of client = -1");
        return;
    }
    QTcpSocket *socket = new QTcpSocket;                       // сокет для клиента
    socket->setSocketDescriptor(socketDescriptor);
    qDebug()<<tr("Подключился клиент №%1").arg(socketDescriptor);
    connect(socket, &QTcpSocket::readyRead, this, &Server::slotReadyRead);    // если сокет готов для чтения, то вызвать slotReadyRead
    connect(socket, &QTcpSocket::disconnected, this, &Server::slotDeleteSocket);    // если клиент отключился, то удалить его сокет из вектора

    InfoClient isiRead;
    isiRead.socket = socket;
    isiRead.isi = new Isi(d_numClients,this);

    d_numClients++;
    setPath(d_numClients, isiRead);
    qDebug()<<tr("Клиенту №%1 будет передан файл %2").arg(socketDescriptor).arg(QFileInfo(isiRead.isi->path()).fileName());
//    isiRead.isi->load();
    isiRead.hZ = 1;
    isiRead.rowSend = 0;
    isiRead.timerId = -1;

    if (sendToClientInfMsg(isiRead) == true)
    {
        isiRead.timerId = startTimer(constSec/isiRead.hZ);
        d_clients.push_back(isiRead);
    }
    else
    {
        qDebug()<<tr("Клиент №%1 отключился").arg(socketDescriptor);
        socket->disconnectFromHost();
        d_numClients--;
    }
}

void Server::slotReadyRead()           // слот обработки целостности полученных данных от клиента
{
    QTcpSocket *socket =   (QTcpSocket*)sender();  // узнаём сокет того, кто послал сигнал
    QDataStream in(socket);          // создали поток для чтения данных из сокета d_socket
    in.setVersion(QDataStream::Qt_5_14);    // назначаем версию
    if(in.status() == QDataStream::Ok)      // проверяем состояние потока данных, если ok, то:
    {
        bool ok = false;
        in >> ok;
        if (ok==false)
        {
            qDebug()<< tr("Клиент не получил сообщение.");
        }
        else
        {
            qDebug()<< tr("Клиент получил сообщение и готов принимать следующее.");
        }
    }
    else {
        qDebug()<<tr("Ошибка с состоянием потока");
    }
    return;
}

void Server::slotDeleteSocket()                         // удаление сокета отключившегося клиента из вектора сокетов
{
    QTcpSocket *socket = (QTcpSocket*)sender();
    for (int i = 0 ; i < d_clients.size(); i++ )
    {
        if ( socket == d_clients[i].socket)
        {
            d_numClients--;
            d_clients.remove(i);
        }
    }
    socket->deleteLater();
}
bool Server::sendToClientTypeData(InfoClient &client)                  // передача сообщения клиенту
{
    QByteArray data;
    data.clear();
    QString s = getMessage(client.rowSend,client.isi, client);
    if (s.isEmpty())
    {
        qDebug() << tr("Ошибка! Записей в файле нет. Файл: %1").arg(client.isi->path());
        return  false;
    }
    QDataStream outIsi(&data, QIODevice::WriteOnly);
    outIsi.setVersion(QDataStream::Qt_5_14);
    outIsi << quint16(0) << s;
    outIsi.device()->seek(0);
    outIsi << quint16(data.size() - sizeof(quint16));
    client.socket->write(data);

    client.socket->waitForBytesWritten((int)(client.hZ*0.9));     // сервер ждёт 900 млсек (если частота = 1), пока все данные запишутся в сокет
    if(!client.socket->waitForReadyRead(1000/(client.hZ*2)))      // если спустя 500 млсек слот ReadyRead не сработал, т.е. клиент не отправил подтверждение о получении сообщения
        // то вывести в qDebug() время и повторно записать в сокет данные и отправить клинту
    {
        client.socket->write(data);
        if(shetchik() == 3)
        {
            qDebug()<<tr("Ошибка! сообщение клиенту отправлено, подтверждение от клиента не получено");
            shetchik(0);
            return true;    //для отправки след. сообщения
        }
    }
    return true;
}

int Server::shetchik(int zero)
{
    static int i = 0;

    if ( zero == 0)
    {
        return i = 0;
    }
    ++i;
    return i;
}

QString Server::getMessage(int &row, Isi *isi, InfoClient &client)
{
    row++;
    QString message = "data:";
    QString emptyMessage = "";
    if (row <= isi->getRowCount())
    {
        for (int i = 0; i <isi->getColumnCount(); i++)
        {
            QVariant value = isi->getValueItem(row,i);
            message = message + value.toString() + " ";
        }
        message+=(" ");
        qDebug()<<tr("Передана строка: %1").arg(message);
        return message;
    }
    else
    {
        row--;
        qDebug()<< tr("Конец передаваемого файла");
        return emptyMessage;
    }

}

void Server::timerEvent(QTimerEvent *event)     //нужно определить для кого из клиентов сработал event
{
    for(int i = 0 ; i < d_numClients ; i++)
    {
        if(event->timerId() == d_clients.at(i).timerId && d_clients.size()!=0)
        {
            bool ok = sendToClientTypeData(d_clients[i]);
            if (ok==false)
            {
                qDebug() << tr("Ошибка! Возможно клиент отключился");
                static_cast<QTimer>(sender()).stop();
                killTimer(event->timerId());
                d_clients.at(i).socket->disconnectFromHost();
            }
            return;
        }
    }
    return;
}

bool Server::sendToClientTypeFile(InfoClient &client)
{
    QByteArray data;
    data.clear();
    QVariant rowCount = client.isi->getRowCount();
    QString str = "file:" + QFileInfo(client.isi->path()).fileName() + " " + rowCount.toString();
    qDebug()<<tr("Передана строка: %1").arg(str);
    QDataStream outIsi(&data, QIODevice::WriteOnly);
    outIsi.setVersion(QDataStream::Qt_5_14);
    outIsi << quint16(0) << str;
    outIsi.device()->seek(0);
    outIsi << quint16(data.size() - sizeof(quint16));
    client.socket->write(data);

    client.socket->waitForBytesWritten((int)(client.hZ*0.9));     // сервер ждёт 900 млсек (если частота = 1), пока все данные запишутся в сокет
    if(!client.socket->waitForReadyRead(1000/(client.hZ*2)))      // если спустя 500 млсек слот ReadyRead не сработал, т.е. клиент не отправил подтверждение о получении сообщения
        // то вывести в qDebug() время и повторно записать в сокет данные и отправить клинту
    {
        client.socket->write(data);
        if(shetchik() == 3)
        {
            qDebug()<<tr("Ошибка! сообщение клиенту отправлено, подтверждение от клиента не получено");
            shetchik(0);
            return false;
        }
    }
    return true;
}

bool Server::sendToClientTypeHeader(InfoClient &client)
{
    QByteArray data;
    data.clear();
    QString str = "header:";
    for (int i = 0; i < client.isi->getHeaderColumnCount(); i++)
    {
        QVariant value = client.isi->getHeaderValueItem(client.isi->getHeaderRowCount(),i);
        str = str + value.toString() + " ";
    }
    qDebug()<<tr("Передана строка: %1").arg(str);
    QDataStream outHeader(&data, QIODevice::WriteOnly);
    outHeader.setVersion(QDataStream::Qt_5_14);
    outHeader << quint16(0) << str;
    outHeader.device()->seek(0);
    outHeader << quint16(data.size() - sizeof(quint16));
    client.socket->write(data);
    client.socket->waitForBytesWritten((int)(client.hZ*0.9));     // сервер ждёт 900 млсек (если частота = 1), пока все данные запишутся в сокет
    if(!client.socket->waitForReadyRead(1000/(client.hZ*2)))      // если спустя 500 млсек слот ReadyRead не сработал, т.е. клиент не отправил подтверждение о получении сообщения
        // то вывести в qDebug() время и повторно записать в сокет данные и отправить клинту
    {
        client.socket->write(data);
        if(shetchik() == 3)
        {
            qDebug()<<tr("Ошибка! Сообщение клиенту отправлено, подтверждение от клиента не получено");
            shetchik(0);
            return false;
        }
    }
    return true;
}

bool Server::sendToClientInfMsg(InfoClient &client)
{
    if ( sendToClientTypeFile(client) == true)
    {
        if (sendToClientTypeHeader(client) == true)
        {
            return true;
        }
    }
    return false;
}

void Server::setPath(int num_client, InfoClient &isiRead)
{
    if(num_client%3 == 1)
    {
//        isiRead.isi->setPath("./../../IsiClientServer/source/20171128-055348-00.isi");
        isiRead.isi->setPath("./../source/20240416-131511-00.isi");

        return;
    }
    if(num_client%3 == 2)
    {
//        isiRead.isi->setPath("./../../IsiClientServer/source/20240416-131511-00.isi");
        isiRead.isi->setPath("./../source/20240405-143905-00.isi");
        return;
    }
    else
    {
//        isiRead.isi->setPath("./../../IsiClientServer/source/20240419-083955-0s0.isi");
        isiRead.isi->setPath("./../source/20240419-083955-00.isi");

        return;
    }
}
